// 
// SoapTrace.Net - A soap message monitoring utility. 
// 
// Copyright (C) 2004 Matthew Ward
// 
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
// 
// Matthew Ward (mrward@users.sourceforge.net)
// 

using System;
using System.Globalization;
using System.Threading;

namespace SoapTrace.Core.ApplicationFramework
{
	/// <summary>
	/// Single Instance Application framework class.  Replaces the standard
	/// System.Application class for single instance applications.
	/// </summary>
	public sealed class SingleInstanceApplication
	{
		/// <summary>
		/// Single instance mutex.   Held whilst this application is alive.
		/// </summary>
		private static Mutex m_SingleInstanceMutex;

		/// <summary>
		/// Remoting server that allows other instances to communicate.
		/// </summary>
		private static SingleInstanceServer m_InstanceServer;

		/// <summary>
		/// Create a new instance of the object.  Private scope since all the 
		/// methods are static.
		/// </summary>
		private SingleInstanceApplication( )
		{
		}

		/// <summary>
		/// Runs the application context with the given command line.
		/// </summary>
		/// <param name="context">Application context to use for this
		/// application.</param>
		/// <param name="args">Command line arguments passed to the
		/// application.</param>
		/// <returns>The return value to be passed to the Main function.</returns>
		public static int Run( ISingleInstanceApplicationContext context,
			string[ ] args )
		{
			int ReturnCode = 0;

			if( IsFirstInstance( context ) )
			{
				ReturnCode = RunFirstInstance( context, args );
			}
			else
			{
				ReturnCode = RunSecondInstance( context, args );
			}

			return ReturnCode;
		}

		/// <summary>
		/// Detects whether this is the first running instance.
		/// </summary>
		/// <returns></returns>
		public static bool IsFirstInstance( ISingleInstanceApplicationContext context )
		{
			// Create instance mutex
			string MutexName = GetMutexName( context );

			bool IsFirstInstance = false;
			m_SingleInstanceMutex = new Mutex( true, MutexName, out IsFirstInstance );
 
			if( IsFirstInstance )
			{
				// Keep hold of the mutex until the application is terminated.
			}
			else
			{
				m_SingleInstanceMutex.Close( );
				m_SingleInstanceMutex = null;
			}


			return IsFirstInstance;
		}

		/// <summary>
		/// Run the first instance.  Set up the remoting server and then
		/// run the application context.
		/// </summary>
		/// <param name="context">Application context.</param>
		/// <param name="args">Command line arguments.</param>
		/// <returns></returns>
		private static int RunFirstInstance( ISingleInstanceApplicationContext context,
			string[ ] args )
		{
			m_InstanceServer = new SingleInstanceServer( context );
			m_InstanceServer.Register( );

			return context.RunFirstInstance( args );
		}

		/// <summary>
		/// Run the second instance.  Connects to the remoting server and
		/// sends the second instance's command line arguments to the first
		/// instance.
		/// </summary>
		/// <param name="context">Application context.</param>
		/// <param name="args">Command line arguments.</param>
		/// <returns>A return code from the second instance.</returns>
		private static int RunSecondInstance( ISingleInstanceApplicationContext context,
			string[ ] args )
		{
			SingleInstanceClient Client = new SingleInstanceClient( context );

			return Client.RunSecondInstance( args );
		}
		
		/// <summary>
		/// Gets the name of the mutex to be used for this application. The
		/// name includes the user and domain.
		/// </summary>
		/// <param name="context">Application context.</param>
		/// <returns>A mutex name of the form 'MyNamespace.MyApp.Domain.User'</returns>
		private static string GetMutexName( ISingleInstanceApplicationContext context )
		{
			Type ContextType = context.GetType( );

			return String.Format( CultureInfo.InvariantCulture, "{0}.{1}", 
				ContextType.FullName,
				GetUserName( ) );
		}
		
		/// <summary>
		/// Returns the domain name followed by the username if this can
		/// be retrieved from Environment.UserDomainName otherwise it
		/// returns just the username.
		/// </summary>
		/// <returns></returns>
		private static string GetUserName( )
		{
			string UserName = String.Empty;
			
			try
			{
				UserName = String.Concat(Environment.UserDomainName, ".", Environment.UserName);
			}
			catch( Exception )
			{
				UserName = Environment.UserName;
			}
			
			return UserName;
		}
	}
}
